<?php

namespace app\admin\controller\fastflow;

use app\admin\model\Admin;
use app\admin\model\AuthGroup;
use app\admin\model\AuthGroupAccess;
use app\admin\model\fastflow\flow\Bill;
use app\admin\model\fastflow\flow\Config;
use app\admin\model\fastflow\flow\EbillCopy;
use app\admin\model\fastflow\flow\Stamp;
use app\admin\model\fastflow\SignatureLog;
use app\common\controller\Backend;
use fastflow\api;
use think\Exception;


/**
 * 流程运行
 *
 * @icon fa fa-o
 */
class Signature extends Backend
{
    protected $model = null;
    protected $noNeedRight = ['getSelectpageWorkers', 'getPageData', 'getBillCanstampCount', 'preview'];

    public function _initialize()
    {
        parent::_initialize();
        $this->model = new \app\admin\model\fastflow\Signature;
    }

    //发起签章
    public function initiate()
    {
        $params = input('');
        $bill = $params['bill'];
        $bill_id = $params['bill_id'];
        $bill_row = (new api())->getBillRow($bill, $bill_id);
        if (!$bill_row) {
            $this->error('未找到单据，无法进行签章');
        }
        if ($bill_row['initiator_id'] != $this->auth->getUserInfo()['id']) {
            $this->error('该单据不是您发起的，您无权限发起签章');
        }

        $ebill_copy = $this->getEbillCopy($bill, $bill_id);
        if (!$ebill_copy) {
            $this->error('该单据无电子表单，无法进行签章');
        }
        if ($this->request->isAjax()) {
            $singers = $params['signers'];
            if ($singers == '') {
                $this->error('签章人员不能为空');
            }

            $base_png = str_replace('data:image/png;base64,', '', $params['ebill']);
            $base_png = base64_decode($base_png);//png原始码

            $signature = [
                'bill' => $params['bill'],
                'bill_id' => $params['bill_id'],
                'status' => 0,
                'initiator_id' => $this->auth->getUserInfo()['id'],
                'signers' => $params['signers'],
                'ebill' => $params['ebill'],
                'ebill_width' => $params['ebill_width'],
                'ebill_height' => $params['ebill_height'],
                'ebill_copy_id' => $ebill_copy['id'],
                'thumbnail' => $params['thumbnail'],
                'firstsectionwidth' => $params['firstsectionwidth'],
                'firstsectionheight' => $params['firstsectionheight'],
                'png_md5' => md5($base_png),
            ];

            //生成新pdf
            $stamp_result = $this->stampPdf($signature);
            if ($stamp_result['code'] == 0) {
                $this->error($stamp_result['msg']);
            }
            $signature['pdf_file'] = '/' . $stamp_result['file'];
            $signature['pdf_md5'] = md5_file($stamp_result['file']);

            $this->model->save($signature);
            $this->success('操作成功');
        }

        $this->view->assign(['bill' => $bill, 'bill_id' => $bill_id, 'ebill' => $ebill_copy]);

        return $this->view->fetch();
    }

    public function stamp()
    {
        $signature_id = input('id');
        $signature = $this->model->with('ebillCopy')->where(['id' => $signature_id])->find();
        if (!$signature) {
            $this->error('参数错误，未找到签章数据');
        }
        $admin_id = $this->auth->getUserInfo()['id'];
        $signers = explode(',', $signature['signers']);
        $stamped = [];
        if ($signature['stamped'] != '') {
            $stamped = explode(',', $signature['stamped']);
        }
        $remain = array_diff($signers, $stamped);
        if (!in_array($admin_id, $remain)) {
            $this->error('您没有权限进行签章');
        }
        if ($this->request->isAjax()) {
            $params = input('');
            if ($params['ebill'] == $signature['ebill']) {
                $this->error('系统检测到未进行签章，请签章后提交');
            }

            //生成新pdf
            $params['stampeddata'] = json_decode($params['stampeddata'], true);
            $stamp_result = $this->stampPdf($signature, $params['stampeddata']);
            if ($stamp_result['code'] == 0) {
                $this->error($stamp_result['msg']);
            }
            //删除原来的pdf
            if ($signature['pdf_file'] != null) {
                if (file_exists(ltrim($signature['pdf_file'], '/'))) {
                    try {
                        unlink(ltrim($signature['pdf_file'], '/'));
                    } catch (Exception $e) {
                        $this->error($e->getMessage());
                    }
                }
            }

            $stamped[] = $admin_id;
            if (count(array_diff($signers, $stamped)) == 0) {//如果所有人均完成签章
                $signature['status'] = 1;
            }

            $base_png = str_replace('data:image/png;base64,', '', $params['ebill']);
            $base_png = base64_decode($base_png);
            $signature['png_md5'] = md5($base_png);

            $signature['stamped'] = implode(',', $stamped);
            $signature['ebill'] = $params['ebill'];
            $signature['thumbnail'] = $params['thumbnail'];
            $signature['pdf_file'] = '/' . $stamp_result['file'];
            $signature['pdf_md5'] = md5_file($stamp_result['file']);
            $signature['has_certificate'] = $stamp_result['has_certificate'];

            $signature->save();

            (new SignatureLog())->save(['signature_id' => $signature['id'], 'admin_id' => $admin_id]);

            $this->success('操作成功');
        }

        $canUseStampList = $this->getCanUseStamp();
        $this->assignconfig(['thumb_width' => $signature['firstsectionwidth'], 'thumb_height' => $signature['firstsectionheight']]);
        $this->view->assign(['signature' => $signature, 'stampList' => $canUseStampList]);
        return $this->view->fetch();
    }

    public function canstamp()
    {
        $billModel = new Bill();
        $bill_list = $billModel->field(['bill_name', 'bill_table'])->select();

        foreach ($bill_list as &$bill) {//查询可签章数
            $bill = $bill->toArray();
            $bill['canstampCount'] = 0;
            $canstampItems = $this->getCanstampItems($bill);
            $bill['canstampCount'] = count($canstampItems);
        }
        $this->view->assign(['billList' => $bill_list]);
        return $this->view->fetch();
    }

    public function stamped()
    {
        $billModel = new Bill();
        $bill_list = $billModel->field(['bill_name', 'bill_table'])->select();

        foreach ($bill_list as &$bill) {//查询已签章数
            $bill = $bill->toArray();
            $bill['count'] = 0;
            $stampedItems = $this->getStampedItems($bill);
            $bill['count'] = count($stampedItems);
        }
        $this->view->assign(['billList' => $bill_list]);
        return $this->view->fetch();
    }

    public function initiated()
    {
        $billModel = new Bill();
        $bill_list = $billModel->field(['bill_name', 'bill_table'])->select();

        foreach ($bill_list as &$bill) {//查询已发起签章数
            $bill = $bill->toArray();
            $bill['count'] = 0;
            $initiatedItems = $this->getInitiatedItems($bill);
            $bill['count'] = count($initiatedItems);
        }
        $this->view->assign(['billList' => $bill_list]);
        return $this->view->fetch();
    }

    public function preview()
    {
        $signature_id = input('id');
        $signature = $this->model->with('ebillCopy')->where(['id' => $signature_id])->find();
        if (!$signature) {
            $this->error('参数错误，未找到签章数据');
        }
        //检查查看权限，非超级管理员只能查看自己签章的数据
        $admin_id = $this->auth->getUserInfo()['id'];
        $isSuperManager = false;
        $groupAccess = AuthGroupAccess::where('uid', $admin_id)->select();
        foreach ($groupAccess as $access) {
            $groupId = $access['group_id'];
            $group = AuthGroup::find($groupId);
            if ($group['pid'] == 0) {
                $isSuperManager = true;
            }
        }
        if (!$isSuperManager) {
            $signers = explode(',', $signature['signers']);
            $stamped = [];
            if ($signature['stamped'] != '') {
                $stamped = explode(',', $signature['stamped']);
            }
             //4.4.1--
            if (!in_array($admin_id, $stamped) && $admin_id != $signature['initiator_id']) {
            //--
                $this->error('您不是该单据的签章人员，无权限查看');
            }
        }

        $bill = (new Bill())->where(['bill_table' => $signature['bill']])->find();
        $this->view->assign(['signature' => $signature, 'bill' => $bill['bill_name']]);
        return $this->view->fetch();
    }

    public function repeal()
    {
        $signature_id = input('id');
        $signature = $this->model->where(['id' => $signature_id])->find();
        if (!$signature) {
            $this->error('参数错误，未找到签章数据');
        }
        //检查权限
        $admin_id = $this->auth->getUserInfo()['id'];
        if ($signature['initiator_id'] != $admin_id) {
            $this->error('无权限撤销非本人发起的签章申请');
        }
        $signature->delete();
        //删除原来的pdf
        if ($signature['pdf_file'] != null) {
            if (file_exists(ltrim($signature['pdf_file'], '/'))) {
                try {
                    unlink(ltrim($signature['pdf_file'], '/'));
                } catch (Exception $e) {
                    $this->error($e->getMessage());
                }
            }
        }
        $this->success('操作成功');
    }

    public function check()
    {
        if ($this->request->isAjax()) {
            $file = input('file');
            $md5 = md5_file(ltrim($file, '/'));
            $signature = $this->model
                ->where(['pdf_md5' => $md5])
                ->field(['initiator_id', 'ebill_copy_id', 'bill', 'bill_id', 'signers', 'stamped', 'status', 'createtime', 'updatetime','has_certificate'])
                ->with(['ebillCopy', 'admin'])
                ->find();
            if (!$signature) {
                return ['code' => 0];
            }
            $signature['createtime'] = date('Y-m-d H:i:s', $signature['createtime']);
            $signature['updatetime'] = date('Y-m-d H:i:s', $signature['updatetime']);

            //获取单据标题
            $signature['bill_name'] = '';
            $bill_row = (new Bill())->where(['bill_table' => $signature['bill']])->find();
            if ($bill_row) {
                $signature['bill_name'] = $bill_row['bill_name'];
            }
            //获取签章人和已签章人
            $signers = explode(',', $signature['signers']);
            $stamped = explode(',', $signature['stamped']);
            $admin_rows = (new Admin())->where('id', 'in', $signers)->field(['id', 'nickname'])->select();
            $signers_array = [];
            $stamped_array = [];
            foreach ($admin_rows as $row) {
                $signers_array[] = $row['nickname'];
                if (in_array($row['id'], $stamped)) {
                    $stamped_array[] = $row['nickname'];
                }
            }
            $signature['signers'] = implode(',', $signers_array);
            $signature['stamped'] = implode(',', $stamped_array);

            return ['code' => 1, 'signature' => $signature];
        }
        return $this->view->fetch();
    }


    public function getBillCanstampCount()
    {
        $billModel = new Bill();
        $bill_list = $billModel->field(['bill_name', 'bill_table'])->select();
        foreach ($bill_list as &$bill) {//查询可签章数
            $bill = $bill->toArray();
            $bill['canstampCount'] = 0;
            $canstampItems = $this->getCanstampItems($bill);
            $bill['canstampCount'] = count($canstampItems);
        }
        return ['code' => 1, 'msg' => '获取成功', 'bills' => $bill_list];
    }

    public function getPageData()
    {
        $params = input('');
        $action = $params['action'];
        $bill = $params['bill'];
        $page = $params['page'];
        $pageSize = $params['pageSize'];
        $offset = ($page - 1) * $pageSize;
        $items = [];
        if ($action == 'canstamp') {
            $items = $this->getCanstampItems($bill);
        } elseif ($action == 'stamped') {
            $items = $this->getStampedItems($bill);
        } elseif ($action == 'initiated') {
            $items = $this->getInitiatedItems($bill);
        }

        $items = array_slice($items, $offset, $pageSize);
        return ['code' => 1, 'msg' => '获取成功', 'ebills' => $items];
    }

    private function getEbillCopy($bill, $bill_id)
    {
        $ebill_copy = (new EbillCopy())->where(['bill' => $bill, 'bill_id' => $bill_id])->find();
        return $ebill_copy;
    }

    private function getEbillCopyId($bill, $bill_id)
    {
        $ebill_copy = $this->getEbillCopy($bill, $bill_id);
        if ($ebill_copy) {
            $ebill_copy = $ebill_copy->toArray();
            return $ebill_copy['id'];
        }
        return null;
    }

    public function getSelectpageWorkers()
    {
        return (new api())->getSelectpageWorkers();
    }

    //获取指定单据能够签章列表
    private function getCanstampItems($bill)
    {
        $bill_table = '';
        if (is_array($bill)) {
            $bill_table = $bill['bill_table'];
        } elseif (is_string($bill)) {
            $bill_table = $bill;
        }
        $items = [];
        $admin_id = $this->auth->getUserInfo()['id'];
        $signatures = $this->model->where(['bill' => $bill_table, 'status' => 0])
		->field(['id', 'status', 'bill_id', 'thumbnail', 'signers', 'stamped', 'initiator_id', 'ebill_copy_id'])
		->with('ebillCopy')->with('admin')->select();
        foreach ($signatures as $signature) {
            $signers = explode(',', $signature['signers']);
            $stamped = explode(',', $signature['stamped']);
            $remain = array_diff($signers, $stamped);
            if (in_array($admin_id, $remain)) {
				unset($signature['signers']);
				unset($signature['stamped']);
				unset($signature['initiator_id']);
				unset($signature['ebill_copy_id']);
                $items[] = $signature;
            }
        }
        return $items;
    }

    //获取指定单据已签章列表
    private function getStampedItems($bill)
    {
        $bill_table = '';
        if (is_array($bill)) {
            $bill_table = $bill['bill_table'];
        } elseif (is_string($bill)) {
            $bill_table = $bill;
        }
        $items = [];
        $admin_id = $this->auth->getUserInfo()['id'];
        $signatures = $this->model->where(['bill' => $bill_table])
		->field(['id', 'status', 'bill_id', 'thumbnail', 'signers', 'stamped', 'initiator_id', 'ebill_copy_id'])
		->with('ebillCopy')->with('admin')->select();
        foreach ($signatures as $signature) {
            $stamped = explode(',', $signature['stamped']);
            if (in_array($admin_id, $stamped)) {
				unset($signature['signers']);
				unset($signature['stamped']);
				unset($signature['initiator_id']);
				unset($signature['ebill_copy_id']);
                $items[] = $signature;
            }
        }
        return $items;
    }

    //获取指定单据已发起签章列表
    private function getInitiatedItems($bill)
    {
        $bill_table = '';
        if (is_array($bill)) {
            $bill_table = $bill['bill_table'];
        } elseif (is_string($bill)) {
            $bill_table = $bill;
        }
        $admin_id = $this->auth->getUserInfo()['id'];
        $signatures = $this->model->where(['bill' => $bill_table, 'initiator_id' => $admin_id])
		->field(['id', 'status', 'bill_id', 'thumbnail', 'initiator_id', 'ebill_copy_id'])
		->with('ebillCopy')->with('admin')->select();

        return $signatures;
    }

    //获取有权限使用的印章
    private function getCanUseStamp()
    {
        $admin_id = $this->auth->getUserInfo()['id'];
        $group = [];
        $group_access_rows = (new AuthGroupAccess())->where(['uid' => $admin_id])->select();
        foreach ($group_access_rows as $access_row) {
            $group[] = $access_row['group_id'];
        }
        $canUseStampList = [];
        $stampList = (new Stamp())->select();
        foreach ($stampList as $stamp) {
            if ($stamp['scope'] == 1 && $stamp['belongsto'] == $admin_id) {
                $canUseStampList[] = $stamp;
            } elseif ($stamp['scope'] == 2) {
                $auth = json_decode($stamp['auth'], true);
                for ($i = 0; $i < count($auth); $i++) {
                    if ($auth[$i]['scope'] == 1 && $auth[$i]['id'] == $admin_id) {
                        $canUseStampList[] = $stamp;
                        break;
                    } elseif ($auth[$i]['scope'] == 2 && in_array($auth[$i]['id'], $group)) {
                        $canUseStampList[] = $stamp;
                        break;
                    }
                }
            }
        }
        return $canUseStampList;
    }

    private function stampPdf($signature, $stampeddata = [])
    {
        $has_certificate = false;

        $totalWidth = floatval($signature['ebill_width']);
        $totalHeight = floatval($signature['ebill_height']);
        $pageWidth = floatval($signature['firstsectionwidth']);
        $pageHeight = floatval($signature['firstsectionheight']);

        $orientation = $pageWidth >= 1122 ? 'L' : 'P';
        $pageCount = ceil($totalHeight / $pageHeight);

        $imageBase64 = str_replace('data:image/png;base64,', '', $signature['ebill']);

        require_once(ADDON_PATH . 'fastflow' . DS . 'library' . DS . 'TCPDF-main' . DS . 'tcpdf.php');
        $pdf = new \TCPDF($orientation, 'pt', PDF_PAGE_FORMAT, true, 'UTF-8', false);
        // set margins
        $pdf->SetMargins(0, 0, 0);
        $pdf->setPrintHeader(false);
        $pdf->setPrintFooter(false);
        $pdf->SetAutoPageBreak(true, 0);//消除分页符空间，否则图片无法填满页面
        $pdf->setJPEGQuality(100);

        //按比例计算印章在pdf中的偏移及大小
        $scale_width = $pdf->getPageWidth() / $pageWidth;
        $scale_height = $pdf->getPageHeight() / $pageHeight;


        //处理stampeddata
        foreach ($stampeddata as &$data) {
            $data['width'] = floatval(str_replace('px', '', $data['width'])) * $scale_width;
            $data['height'] = floatval(str_replace('px', '', $data['height'])) * $scale_height;
            $data['pageNumber'] = ceil($data['top'] / $pageHeight);
            $data['left'] = $data['left'] * $scale_width;
            $data['top'] = fmod($data['top'], $pageHeight) * $scale_height;
            $data['stamp'] = ((new Stamp())->where(['id' => $data['id']])->find())['file'];
        }

        //读取签名验证配置
        $configModel = new Config();
        $canSignature = false;
        $certificate = '';
        $privatekey = '';
        $config_signature = $configModel->where(['name' => 'signature'])->find()->toArray();
        if ($config_signature['value'] == 'true') {
            $canSignature = true;
            $certificate = $configModel->where(['name' => 'certificate'])->find()->toArray()['value'];
            $privatekey = $configModel->where(['name' => 'privatekey'])->find()->toArray()['value'];
            if ($certificate == '' || $privatekey == '') {
                return ['code' => 0, 'msg' => '证书或私钥不正确'];
            }
        }
        $signature_info = array(
            'Name' => '',
            'Location' => '',
            'Reason' => '我确认对该单据进行批准',
            'ContactInfo' => '',
        );

        for ($i = 0; $i < $pageCount; $i++) {
            $pdf->AddPage($orientation, "A4", true, false);
            $pageImgdata = $this->catImage($imageBase64, 0, $i * $pageHeight, $pageWidth, $pageHeight);
            $pdf->Image('@' . $pageImgdata);
            //添加印章
            foreach ($stampeddata as $item) {
                if ($item['pageNumber'] == ($i + 1)) {
                    $pdf->Image('.' . $item['stamp'], $item['left'], $item['top'], $item['width'], $item['height']);
                    //添加电子签名
                    if ($canSignature) {
                        $pdf->setSignatureAppearance($item['left'], $item['top'], $item['width'], $item['height']);
                        $pdf->setSignature($certificate, $privatekey, '', '', 2, $signature_info, 'A');
                        $has_certificate = true;
                    }
                }
            }
        }
        try {
            $pdfDir = 'uploads/fastflow/signature/';
            if (!file_exists($pdfDir)) {
                if (!mkdir($pdfDir, 0777, true)) {
                    return ['code' => 0, 'msg' => '错误：无法创建文件目录'];
                }
            }
            $pdfPath = $pdfDir . md5(uniqid(mt_rand(), true)) . '.pdf';
            $pdf->Output($_SERVER['DOCUMENT_ROOT'] . $pdfPath, 'F');

            return ['code' => 1, 'msg' => '生成PDF文件成功', 'file' => $pdfPath, 'has_certificate' => $has_certificate];
        } catch (Exception $e) {
            return ['code' => 0, 'msg' => $e->getMessage()];
        }

    }

    /**
     * @param $base64data
     * @param $x //裁剪区域左上角的点的坐标x
     * @param $y //裁剪区域左上角的点的坐标y
     * @param $width //裁剪区域的宽
     * @param $height //裁剪区域的高
     * @return string //base64
     */
    private function catImage($base64data, $x, $y, $width, $height)
    {
        $old_image_base64 = base64_decode($base64data);
        $old_image = imagecreatefromstring($old_image_base64);

        //将裁剪区域复制到新图片上，并根据源和目标的宽高进行缩放或者拉升
        $new_image = imagecreatetruecolor($width, $height);
        imagecopyresampled($new_image, $old_image, 0, 0, $x, $y, $width, $height, $width, $height);
        //imagejpeg($new_image,'1.jpg');

        ob_start(); // 打开输出控制缓冲
        imagejpeg($new_image); //未打开输出控制缓冲，会输出图象到浏览器或文件，打开输出控制缓冲后则不会
        imagedestroy($new_image);//销毁图像
        $contents = ob_get_contents(); //返回输出缓冲区的内容
        ob_end_clean(); //清空（擦除）缓冲区并关闭输出缓冲
        //输出base64
        return $contents;
    }

}